package club.kynb.mall.order.service.impl;

import club.kynb.mall.order.api.IOrderService;
import club.kynb.mall.order.constant.OrderCancelTypeEnum;
import club.kynb.mall.order.constant.OrderConfirmTypeEnum;
import club.kynb.mall.order.constant.OrderStatusEnum;
import club.kynb.mall.order.convert.OrderConvertor;
import club.kynb.mall.order.model.dto.*;
import club.kynb.mall.order.mysql.mapper.OrderDetailMapper;
import club.kynb.mall.order.mysql.mapper.OrderMapper;
import club.kynb.mall.order.mysql.po.OrderDetailPO;
import club.kynb.mall.order.mysql.po.OrderPO;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pizza.common.web.exception.Errors;
import org.pizza.model.page.PageResult;
import org.pizza.mybatis.plus.support.Pages;
import org.pizza.util.Checker;
import org.pizza.util.Convertor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kynb_club@163.com
 * @since 2021/6/29 8:40 下午
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderServiceImpl implements IOrderService {

    private final OrderMapper orderMapper;
    private final OrderDetailMapper orderDetailMapper;


    @Override
    public boolean existsOrderNo(String innerOrderNo) {
        Optional<OrderPO> first = orderMapper.selectList(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo)).stream().findFirst();
        return first.isPresent();
    }

    @Override
    public List<OrderDetailDTO> listOrderDetail(String orderNo) {
        List<OrderDetailPO> listDetail = orderDetailMapper.selectList(Wrappers.<OrderDetailPO>lambdaQuery().eq(OrderDetailPO::getInnerOrderNo, orderNo));
        return OrderConvertor.convert(listDetail, OrderDetailDTO.class);
    }

    @Override
    public List<OrderDetailDTO> listOrdersDetail(List<String> orderNos) {
        List<OrderDetailPO> listDetail = orderNos.stream()
                .map(orderNo -> orderDetailMapper.selectList(Wrappers.<OrderDetailPO>lambdaQuery().eq(OrderDetailPO::getInnerOrderNo, orderNo)))
                .flatMap(Collection::stream).collect(Collectors.toList());
        return OrderConvertor.convert(listDetail, OrderDetailDTO.class);
    }

    @Override
    public Optional<OrderAndDetailsDTO> getByOrderAndDetails(String innerOrderNo) {
        OrderPO orderPO = orderMapper.selectOne(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo));
        if (orderPO == null) {
            return Optional.empty();
        }
        OrderAndDetailsDTO orderAndDetailsDTO = OrderConvertor.convert(OrderAndDetailsDTO.class, orderPO);
        List<OrderDetailPO> listDetail = orderDetailMapper.selectList(Wrappers.<OrderDetailPO>lambdaQuery().eq(OrderDetailPO::getInnerOrderNo, innerOrderNo));
        if (CollectionUtil.isEmpty(listDetail)) {
            return Optional.empty();
        }
        orderAndDetailsDTO.setDetails(OrderConvertor.convert(listDetail, OrderDetailDTO.class));
        return Optional.of(orderAndDetailsDTO);
    }

    @Override
    public PageResult<OrderAndDetailsDTO> orderHistoryPageQuery(OrderHistoryPageQuery orderHistoryPageQuery) {
        final LambdaQueryWrapper<OrderPO> queryWrapper = Wrappers.<OrderPO>lambdaQuery()
                .eq(OrderPO::getUserId, orderHistoryPageQuery.getUserId());

        if (StrUtil.isNotBlank(orderHistoryPageQuery.getOrderStatusString())) {
            final String[] statusArray = orderHistoryPageQuery.getOrderStatusString().split(",");
            final List<String> statusList = Arrays.asList(statusArray);
            final List<String> collect = statusList.stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
            queryWrapper.in(OrderPO::getOrderStatus, collect);
        }
        queryWrapper.orderByDesc(OrderPO::getCreateTime);
        //mybatis page转换
        IPage<OrderPO> pageParam = Pages.convert(orderHistoryPageQuery);
        //分页查询
        IPage<OrderPO> page = orderMapper.selectPage(pageParam, queryWrapper);
        final PageResult<OrderAndDetailsDTO> pageResult = Pages.convert(page, OrderAndDetailsDTO.class);
        pageResult.getRecords().forEach(orderAndDetailsDTO -> {
            List<OrderDetailPO> listDetail = orderDetailMapper.selectList(Wrappers.<OrderDetailPO>lambdaQuery().eq(OrderDetailPO::getInnerOrderNo, orderAndDetailsDTO.getInnerOrderNo()));
            orderAndDetailsDTO.setDetails(OrderConvertor.convert(listDetail, OrderDetailDTO.class));
        });
        return pageResult;
    }

    @Override
    public void updateByOrderNo(OrderDTO dto) {
        OrderPO orderPO = OrderConvertor.convert(OrderPO.class, dto);
        int update = orderMapper.update(orderPO, Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, dto.getInnerOrderNo()));
        Checker.ifNotThrow(update > 0, () -> Errors.SYSTEM.exception("系统异常，订单信息更新失败"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOrder(OrderDTO orderDTO, List<OrderDetailDTO> orderDetailList) {
        final List<OrderDetailPO> detailPOList = Convertor.convert(orderDetailList, OrderDetailPO.class);
        final OrderPO orderPO = Convertor.convert(OrderPO.class, orderDTO);
        final int insert1 = orderMapper.insert(orderPO);
        Checker.ifNotThrow(insert1 > 0, () -> Errors.SYSTEM.exception("系统异常，持久化订单信息失败"));
        detailPOList.forEach(orderDetailPO -> {
            final int insert2 = orderDetailMapper.insert(orderDetailPO);
            Checker.ifNotThrow(insert2 > 0, () -> Errors.SYSTEM.exception("系统异常，持久化订单详情信息失败"));
        });
    }

    @Override
    public void orderCancel(String innerOrderNo, OrderCancelTypeEnum cancelTypeEnum, String cancelDesc) {
        OrderPO orderPO = orderMapper.selectOne(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo));
        Checker.ifNullThrow(orderPO, () -> Errors.BIZ.exception("传入订单编号有误，订单不存在"));
        Checker.ifNotThrow(orderPO.getOrderStatus().equals(OrderStatusEnum.UNPAID.code()), () -> Errors.BIZ.exception("当前订单状态，无法取消订单"));
        orderPO.setOrderStatus(OrderStatusEnum.CANCELLED.code());
        orderPO.setCancelDesc(cancelDesc);
        orderPO.setCancelType(cancelTypeEnum.code());
        orderPO.setCancelTime(new Date());
        orderMapper.updateById(orderPO);
    }

    @Override
    public Optional<OrderDTO> getOrderBy(String innerOrderNo) {
        OrderPO orderPO = orderMapper.selectOne(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo));
        if (orderPO == null) {
            return Optional.empty();
        }
        return Optional.of(Convertor.convert(OrderDTO.class, orderPO));
    }

    @Override
    public void orderConfirm(String innerOrderNo, OrderConfirmTypeEnum confirmTypeEnum) {
        OrderPO orderPO = orderMapper.selectOne(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo));
        Checker.ifNullThrow(orderPO, () -> Errors.BIZ.exception("传入订单编号有误，订单不存在"));
        Checker.ifNotThrow(orderPO.getOrderStatus().equals(OrderStatusEnum.UN_RECEIVE.code()), () -> Errors.BIZ.exception("当前订单状态，无法取消订单"));
        orderPO.setOrderStatus(OrderStatusEnum.FINISHED.code());
        orderMapper.updateById(orderPO);
    }

    @Override
    public void applyRefund(String innerOrderNo) {
        OrderPO orderPO = orderMapper.selectOne(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo));
        Checker.ifNullThrow(orderPO, () -> Errors.BIZ.exception("传入订单编号有误，订单不存在"));
        Checker.ifNotThrow(orderPO.getOrderStatus().equals(OrderStatusEnum.UN_DELIVERY.code())
                || orderPO.getOrderStatus().equals(OrderStatusEnum.UN_RECEIVE.code()), () -> Errors.BIZ.exception("当前订单状态，无法申请退款"));
        orderPO.setOrderStatus(OrderStatusEnum.WAITING_REFUND.code());
        orderMapper.updateById(orderPO);
    }

    @Override
    public void applyRefundCancel(String innerOrderNo, String orderOriginalStatus) {
        OrderPO orderPO = orderMapper.selectOne(Wrappers.<OrderPO>lambdaQuery().eq(OrderPO::getInnerOrderNo, innerOrderNo));
        Checker.ifNullThrow(orderPO, () -> Errors.BIZ.exception("传入订单编号有误，订单不存在"));
        Checker.ifNotThrow(orderPO.getOrderStatus().equals(OrderStatusEnum.WAITING_REFUND.code()), () -> Errors.BIZ.exception("订单状态已变更，请刷新重试"));
        orderPO.setOrderStatus(orderOriginalStatus);
        orderMapper.updateById(orderPO);
    }


    @Override
    public PageResult<OrderDTO> orderPage(OrderPageQuery query) {
        final LambdaQueryWrapper<OrderPO> queryWrapper = Wrappers.<OrderPO>lambdaQuery();
        if (StrUtil.isNotBlank(query.getOrderStatus())) {
            queryWrapper.eq(OrderPO::getOrderStatus, query.getOrderStatus());
        }
        queryWrapper.orderByDesc(OrderPO::getCreateTime);
        //mybatis page转换
        IPage<OrderPO> pageParam = Pages.convert(query);
        //分页查询
        IPage<OrderPO> page = orderMapper.selectPage(pageParam, queryWrapper);
        final PageResult<OrderDTO> pageResult = Pages.convert(page, OrderDTO.class);
        return pageResult;
    }


}
